#include "stddef.h"
#include "pt_config.h"
#include "pt_god_schedule.h"
#include "ptdebug.h"
#include "pt_timer.h"
#include "pt_mem.h"
#include "pt.h"

//STATIC_ASSERT(sizeof(void *) == 4, "only support 32-bit platform");
extern char (*_do_assert(void)) [sizeof(char[1 - 2*!(sizeof(void *) == 4)])];

static PT_THREAD(  system_thread_entry(struct pt *pt) )
{
    PT_BEGIN ( pt );
    static struct timer tm;
    while(1){

        timer_set(&tm, MS_TO_TICK(2000) );
        PT_WAIT_UNTIL(pt, timer_expired(&tm) );
        extern struct mem_stat_str * get_mem_stat(void);
        struct mem_stat_str *p_mem_stat;
        p_mem_stat = get_mem_stat();
        (void)p_mem_stat;
        uint32_t get_mem_stat_max(void);
        uint32_t mem_stat_max;
        mem_stat_max = get_mem_stat_max();
        uint32_t i;
        for (i = 0; i < mem_stat_max; i++){
            if (p_mem_stat[i].thread != PT_NULL){

                PT_DEBUG_LOG(PT_LOG_LEVEL_KERNEL, ("malloc thread = %p\n", p_mem_stat[i].thread ) );
                PT_DEBUG_LOG(PT_LOG_LEVEL_KERNEL, ("thread id = 0x%X\n", p_mem_stat[i].thread->thread_id) );
                PT_DEBUG_LOG(PT_LOG_LEVEL_KERNEL, ("nearest line = %d\n", (int)p_mem_stat[i].thread->lc ) );

            }else{

                break;
            }

        }
        PT_DEBUG_LOG(PT_LOG_LEVEL_KERNEL, ("mem_remaining = %d\n", get_mem_remaining()) );
        PT_DEBUG_LOG(PT_LOG_LEVEL_KERNEL, ("no free mem count = %d\n", i) );

        PT_YIELD(pt);
        if (0){break;}	// 消除PT_END无法执行到的警告
    }

    PT_END( pt );
}
static struct pt system_thread = {
    .alive              = PT_PROCESS_ALIVE,
    .suspend_state      = PT_PROCESS_RESUME,
    .entry              = system_thread_entry,
    .tlist.next         = &system_thread.tlist,
    .tlist.prev         = &system_thread.tlist,
    .thread_id          = 0x0F,
    .mb_thread          = PT_NULL,

};                         // 系统协程, 只是用来做链表头

static uint8_t list_cur_cnt = 1;							// 当前协程数量

static struct pt *cur_thread = &system_thread;          // 开始时指向系统协程

static int32_t pt_thread_delete(struct pt * thread);


/**
 *@description: 上帝调度器, 初始化了协程后, 可在后台调用这个函数, 隐式调度所有协程
 *@param: NA
 *@return: NA
 *@author: Kalimdorsummer
 *@date: 2020-03-12 11:10:18
*/
void pt_god_schedule(void)
{
    while(1){
		//协程数大于0才调度
        if(list_cur_cnt > 0){
			//协程还活着
			if ( (cur_thread->alive) != PT_PROCESS_DEAD ) {
                //并且未挂起才调度
                if( cur_thread->suspend_state != PT_PROCESS_SUSPEND ){
                    if ( cur_thread->entry != NULL ){       //入口函数已配置
                        cur_thread->entry(cur_thread);
                    }
                }
                //根据链表位置找到结构体入口
                //找到下一个协程的入口地址
                if (cur_thread->tlist.next == PT_NULL){
                    PT_DEBUG_LOG(PT_LOG_LEVEL_KERNEL, ("tlist.next NULL\n") );
                }
				cur_thread = pt_list_entry(cur_thread->tlist.next, struct pt, tlist);
			}else{
//				pt_list_t tmp_list = cur_thread->tlist;
				pt_list_remove(&cur_thread->tlist);                             //将当前线程移除出线程列表
				list_cur_cnt--;                                                 //当前线程数量减一
#ifdef PT_USING_MEM_HEAP
                if( is_heap_mem(cur_thread) ){
                    pt_thread_delete(cur_thread);   //释放当前线程
                }
#endif // PT_USING_MEM_HEAP
//                cur_thread = pt_list_entry(tmp_list.next, struct pt, tlist);
                cur_thread = &system_thread;

			}

        }
    }
}

/**
 * This function is the timeout function for thread, normally which is invoked
 * when thread is timeout to wait some resource.
 *
 * @param parameter the parameter of thread timeout function
 */
static void pt_thread_timeout(void *parameter)
{
    struct pt *thread;

    thread = (struct pt *)parameter;

    /* thread check */
    PT_ASSERT(thread != PT_NULL);
    /* set error number */
//    thread->error = -RT_ETIMEOUT;

    // 假设该线程被挂起了, 超时后把它移除出挂起点, 后面会将它插入运行链表
    pt_list_remove(&(thread->tlist));

    /* insert to schedule ready list */
    pt_schedule_insert_thread(thread);

    /* do schedule */
//    rt_schedule();
//    PT_RESUME(thread);
}

#ifdef PT_USING_MEM_HEAP
/**
 * This function will create a thread object and allocate thread object memory
 * and stack.
 *
 * @param name the name of thread, which shall be unique
 * @param entry the entry function of thread
 * @param parameter the parameter of thread enter function
 * @param stack_size the size of thread stack
 * @param priority the priority of thread
 * @param tick the time slice if there are same priority thread
 *
 * @return the created thread object
 */
struct pt *pt_thread_create( uint16_t thread_id, PT_THREAD( (*entry)(struct pt *pt) ) )
{
    PT_ASSERT(entry != PT_NULL);
    struct pt *thread;

    thread = (struct pt *)kernel_malloc( sizeof(struct pt) );

    if (thread == PT_NULL){
        return PT_NULL;
    }

    pt_thread_init(thread, entry);
    pt_set_thread_id(thread, thread_id);
    return thread;
}

/**
 * This function will delete a thread. The thread object will be removed from
 * thread queue and deleted from system object management in the idle thread.
 *
 * @param thread the thread to be deleted
 *
 * @return the operation status, RT_EOK on OK, -RT_ERROR on error
 */
static int32_t pt_thread_delete(struct pt * thread)
{
    /* thread check */
    PT_ASSERT(thread != PT_NULL);

//    if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_INIT)
//    {
//        /* remove from schedule */
//        rt_schedule_remove_thread(thread);
//    }



        pt_free(thread->mb_thread); //释放掉邮箱, 若邮箱为空, 无需担心free
        pt_free(thread);

    /* release thread timer */
//    rt_timer_detach(&(thread->thread_timer));

    /* change stat */
//    thread->stat = RT_THREAD_CLOSE;

    /* disable interrupt */
//    pt_hw_interrupt_disable();

    /* insert to defunct thread list */
//    rt_list_insert_after(&rt_thread_defunct, &(thread->tlist));

    /* enable interrupt */
//    pt_hw_interrupt_enable();

    return PT_EOK;
}
#endif

/**
 *@description: 初始化协程
 *@param: pt_ins,协程实例, entry, 协程入口
 *@return: 初始化状态
 *@author: Kalimdorsummer
 *@date: 2020-03-12 11:08:49
*/
uint8_t pt_thread_init(struct pt *pt_ins, PT_THREAD(  (*entry)(struct pt *pt) ) )
{
    PT_ASSERT(entry != PT_NULL);

	//超出最大协程数
    if(list_cur_cnt >= LIST_MAX){
        PT_DEBUG_LOG ( PT_LOG_LEVEL_DEBUG, ( "INIT_EXCEED_MAX\n" ) );
        return INIT_EXCEED_MAX;
    }


    //判断是否重复初始化
    struct pt_list_node *temp = &system_thread.tlist;

    do{
        //重复初始化了
        if ( temp == &pt_ins->tlist)
            return INIT_RE_INIT;

        temp = temp->next;
    }while(temp != &system_thread.tlist);

    pt_list_insert_after(&system_thread.tlist, &pt_ins->tlist);

	pt_ins->entry = entry;	//初始化入口函数
	pt_ins->suspend_state = 1;  //初始化挂起状态, 非挂起

	PT_INIT(pt_ins);

	pt_ins->thread_id = PT_NULL;    //默认无ID
    list_cur_cnt++;

    //初始化内部定时器
    pt_timer_init(  &(pt_ins->thread_timer),        //用的是实体, 传入地址
                    PT_NULL,                        //名称无
                    pt_thread_timeout,              //超时回调函数
                    pt_ins,                         //线程作为回调时的参数
                    0,                              //定时时间初始化为0
                    PT_NULL );                      //无标志

    return INIT_OK;
}
/**
 *@description: 初始化线程id, 若id重复则返回失败
 *@param: pt_ins,协程实例, thread_id, id值
 *@return: 初始化状态
 *@author: Kalimdorsummer
 *@date: 2020-04-5 19:08:49
*/
uint8_t pt_set_thread_id(struct pt *pt_ins, uint16_t thread_id)
{

    //========查询列表中id是否重复==========
    struct pt_list_node *temp = &system_thread.tlist;

    struct pt *tmp_thread;

    do{
        tmp_thread = pt_list_entry(temp, struct pt, tlist);
        //id重复了
        if(tmp_thread->thread_id == thread_id){
            PT_DEBUG_LOG(PT_LOG_LEVEL_DEBUG, ("thread id redefined:%d\n", thread_id) );
            return PT_ERROR;
        }

        temp = temp->next;
    }while(temp != &system_thread.tlist);
    //=============================================================

    pt_ins->thread_id = thread_id;
    return PT_EOK;
}

struct pt *get_cur_thread(void)
{
    return cur_thread;
}


/**
 * This function will let current thread sleep for some ticks.
 *
 * @param tick the sleep ticks
 *
 * @return PT_EOK
 */
int32_t pt_thread_sleep(int32_t tick)
{
    struct pt *thread;

    pt_hw_interrupt_disable();

    thread = cur_thread;
    PT_ASSERT(thread != PT_NULL);

    /* suspend thread */
    pt_thread_suspend(thread);

    // 如果是PT_WAITING_FOREVER, 那就是负数, 不启动定时器
    if (tick > 0){
        /* reset the timeout of thread timer and start it */
        pt_timer_control(&(thread->thread_timer), PT_TIMER_CTRL_SET_TIME, &tick);
        pt_timer_start(&(thread->thread_timer));
    }


    /* enable interrupt */
    pt_hw_interrupt_enable();

    return PT_EOK;
}

/**
 *@description: 移除协程
 *@thread: 要移除的协程
 *@return: NA
 *@author: Kalimdorsummer
 *@date: 2020-08-01 11:37:19
*/
static void pt_schedule_remove_thread(struct pt *thread)
{
    PT_ASSERT(thread != PT_NULL);


    pt_hw_interrupt_disable();

    if (cur_thread == thread){
        pt_list_t tmp_list = cur_thread->tlist;
        cur_thread = pt_list_entry(tmp_list.next, struct pt, tlist);
    }

    pt_list_remove(&(thread->tlist));


    pt_hw_interrupt_enable();
}

/**
 *@description: 挂起协程
 *@thread: 要挂起的协程
 *@return: PT_EOK
 *@author: Kalimdorsummer
 *@date: 2020-08-01 11:35:53
*/
int32_t pt_thread_suspend(struct pt *thread)
{
    /* thread check */
    PT_ASSERT(thread != PT_NULL);

//    stat = thread->stat & RT_THREAD_STAT_MASK;
    thread->suspend_state = PT_PROCESS_SUSPEND;

    /* disable interrupt */
    pt_hw_interrupt_disable();

    /* change thread stat */
    pt_schedule_remove_thread(thread);
//    thread->stat = RT_THREAD_SUSPEND | (thread->stat & ~RT_THREAD_STAT_MASK);

    /* stop thread timer anyway */
//    pt_timer_stop(&(thread->thread_timer));

    /* enable interrupt */
    pt_hw_interrupt_enable();

    return PT_EOK;
}

/**
 *@description: 向运行链表插入协程
 *@thread: 要插入的协程
 *@return: NA
 *@author: Kalimdorsummer
 *@date: 2020-08-01 11:34:41
*/
void pt_schedule_insert_thread(struct pt *thread)
{
    PT_ASSERT(thread != PT_NULL);

    /* disable interrupt */
    pt_hw_interrupt_disable();

    // 如果插入的是当前运行的, 那就是无用功, 标记运行即可退出
    if (thread == cur_thread){
        thread->suspend_state = PT_PROCESS_RESUME;
        goto __exit;
    }

    thread->suspend_state = PT_PROCESS_RESUME;

    // 插入到系统线程后
    pt_list_insert_after(&system_thread.tlist, &thread->tlist);
    // 插入到当前线程后, 可快速切换到获取了资源的线程, 可能造成两个线程互相唤醒对方, 造成别的线程饥饿
//    pt_list_insert_after(&system_thread.tlist, &thread->tlist);

__exit:
    /* enable interrupt */
    pt_hw_interrupt_enable();
}

/**
 *@description: 恢复协程运行
 *@thread: 要恢复的协程
 *@return: PT_EOK
 *@author: Kalimdorsummer
 *@date: 2020-08-01 11:33:41
*/
int32_t pt_thread_resume(struct pt *thread)
{
    /* thread check */
    PT_ASSERT(thread != PT_NULL);

    /* disable interrupt */
    pt_hw_interrupt_disable();

    /* remove from suspend list */
    pt_list_remove(&(thread->tlist));

    pt_timer_stop(&thread->thread_timer);

    /* insert to schedule ready list */
    pt_schedule_insert_thread(thread);

    /* enable interrupt */
    pt_hw_interrupt_enable();

    return PT_EOK;
}
